/*
 * Copyright 2007 National Bioinformatics Network
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package queryexecute;

import java.util.HashMap;
import java.util.Map;

import org.jgrapht.DirectedGraph;
import org.jgrapht.graph.DefaultDirectedGraph;
import org.omg.CORBA.TCKind;
import org.omg.CORBA.TypeCode;
import org.omg.CORBA.TypeCodePackage.BadKind;

import dgbgui.logging.ErrorLogger;
import dgbgui.modeldocument.primitives.Attribute;
import dgbgui.modeldocument.primitives.AttributeType;
import dgbgui.modeldocument.primitives.Concept;
import dgbgui.modeldocument.primitives.ConceptType;
import dgbgui.modeldocument.primitives.DataType;
import dgbgui.modeldocument.primitives.DefaultAnnotatedEdge;
import dgbgui.modeldocument.primitives.Graph;
import dgbgui.modeldocument.primitives.Layer;
import dgbgui.modeldocument.primitives.LayerType;
import dgbgui.modeldocument.primitives.Primitive;
import dgbgui.modeldocument.primitives.Relation;
import dgbgui.modeldocument.primitives.RelationType;
import dgbgui.modeldocument.primitives.Variant;

public class CorbaToNativeConverter {
    
    public static Variant convert(org.omg.CORBA.Any any) {
        if ( any.type().kind() == org.omg.CORBA.TCKind.tk_boolean ) {
            return new Variant(Variant.Type.BOOLEAN,0);
        }
        if ( any.type().kind() == org.omg.CORBA.TCKind.tk_string ) {
            return new Variant(Variant.Type.STRING,(String)any.extract_string());
        }
        if ( any.type().kind() == org.omg.CORBA.TCKind.tk_long ) {
            return new Variant(Variant.Type.LONG,(long)any.extract_long());
        }
        if ( any.type().kind() == org.omg.CORBA.TCKind.tk_ulong ) {
            return new Variant(Variant.Type.LONG,(long)any.extract_long());
        }
        if ( any.type().kind() == org.omg.CORBA.TCKind.tk_short ) {
            return new Variant(Variant.Type.SHORT,(short)any.extract_short());
        }
        if ( any.type().kind() == org.omg.CORBA.TCKind.tk_ushort ) {
            return new Variant(Variant.Type.SHORT,(short)any.extract_short());
        }
        if ( any.type().kind() == org.omg.CORBA.TCKind.tk_float ) {
            return new Variant(Variant.Type.FLOAT,(float)any.extract_short());
        }
        if ( any.type().kind() == org.omg.CORBA.TCKind.tk_double ) {
            return new Variant(Variant.Type.DOUBLE,(double)any.extract_short());
        }

        return null;
    }

    public static DataType convert(dgbCORBA.data_type_t dataType) {
        return new DataType(dataType.id,dataType.name);
    }
    
    public static AttributeType convert(dgbCORBA.attribute_t attributeType) {
        return new AttributeType(
                attributeType.id,
                attributeType.data_type_id,
                attributeType.name,
                attributeType.cardinality,
                attributeType.is_required,
                attributeType.is_unique,
                attributeType.is_identifier
                );
    }
    
    public static AttributeType[] convert(dgbCORBA.attribute_t[] attributeTypes) {
        int arrayLength = attributeTypes.length;
        AttributeType[] converted = new AttributeType[arrayLength];
        for ( int k = 0; k < arrayLength; ++k ) {
            converted[k] = convert(attributeTypes[k]);
        }
        return converted;
    }
    
    public static Attribute convert(dgbCORBA.attrib attribute) {
        return new Attribute(attribute.id,attribute.data_type_id,
                convert(attribute.value));
    }
    
    public static Attribute[] convert(dgbCORBA.attrib[] attributes) {
        int arrayLength = attributes.length;
        Attribute[] converted = new Attribute[arrayLength];
        for ( int k = 0; k < arrayLength; ++k ) {
            converted[k] = convert(attributes[k]);
        }
        return converted;
    }

    public static ConceptType convert(dgbCORBA.concept_t conceptType) {
        AttributeType[] convertedAttributeTypes = convert(conceptType.attributes);
        return new ConceptType(conceptType.id,conceptType.name,convertedAttributeTypes);
    }
    
    public static RelationType convert(dgbCORBA.relation_t relationType) {
        AttributeType[] convertedAttributeTypes = convert(relationType.attributes);
        return new RelationType(relationType.id,relationType.name,convertedAttributeTypes);
    }
    
    public static LayerType convert(dgbCORBA.layer_t layerType) {
        AttributeType[] convertedAttributeTypes = convert(layerType.attributes);
        return new LayerType(layerType.id,layerType.name,convertedAttributeTypes);
    }
    

    
    public static Concept convert(dgbCORBA.concept concept) {
        Attribute[] convertedAttributes = convert(concept.attributes);
        return new Concept(concept.id,concept.type_id,convertedAttributes);
    }
    
    public static Relation convert(dgbCORBA.relation relation) {
        Attribute[] convertedAttributes = convert(relation.attributes);
        return new Relation(relation.id,relation.type_id,convertedAttributes);
    }

    public static Layer convert(dgbCORBA.layer layer) {
        Attribute[] convertedAttributes = convert(layer.attributes);
        return new Layer(layer.id,layer.type_id,convertedAttributes);
    }
    

    public static Graph convert(dgbCORBA.dgb_graph graph) {
        
        // Temporary map for the conversion
        Map<Long,Primitive> gidMap = new HashMap<Long,Primitive>(graph.node_list.length);
        
        DirectedGraph<Primitive,DefaultAnnotatedEdge> primtiveGraph = 
            new DefaultDirectedGraph<Primitive,DefaultAnnotatedEdge>(DefaultAnnotatedEdge.class);
        
        for ( dgbCORBA.dgb_node n : graph.node_list ) {

            TypeCode type = n.vertex.type();
            TCKind kind = type.kind();
            switch (kind.value()) { 
            case TCKind._tk_struct:
                Primitive p = getPrimitive(n.vertex);
                gidMap.put(n.gid,p);
                primtiveGraph.addVertex(p);
                break;
            default: assert false;
            }
        }   
        
        for ( dgbCORBA.dgb_edge e : graph.edge_list ) {
            primtiveGraph.addEdge(
                    gidMap.get(e.source_gid), 
                    gidMap.get(e.target_gid), 
                    new DefaultAnnotatedEdge(e.annotation));
        }
        
        return new Graph(primtiveGraph);
    }
    
    public static Primitive getPrimitive(org.omg.CORBA.Any any) {
        TypeCode type = any.type();
        String name = "";
        try {
            name = type.name();
        } catch (BadKind e) {
            ErrorLogger.getInstance().logException(e);
        }
        Primitive primitive = null;
        // Using the appropriate helper, convert the CORBA primivitce
        // into a native primitive
        if ("concept_t".equals(name)) {
            primitive = CorbaToNativeConverter.convert(dgbCORBA.concept_tHelper.extract(any));
        } else if ("concept".equals(name)) {
            primitive = CorbaToNativeConverter.convert(dgbCORBA.conceptHelper.extract(any));
        } else if ("relation_t".equals(name)) {
            primitive = CorbaToNativeConverter.convert(dgbCORBA.relation_tHelper.extract(any));
        } else if ("relation".equals(name)) { 
            primitive = CorbaToNativeConverter.convert(dgbCORBA.relationHelper.extract(any));
        } else if ("layer_t".equals(name)) {
            primitive = CorbaToNativeConverter.convert(dgbCORBA.layer_tHelper.extract(any));
        } else if ("layer".equals(name)) { 
            primitive = CorbaToNativeConverter.convert(dgbCORBA.layerHelper.extract(any));
        } else if ("dgb_graph".equals(name)) {
            primitive = CorbaToNativeConverter.convert(dgbCORBA.dgb_graphHelper.extract(any));
        } else {
            assert false;
        }
        return primitive;
    }

    
}
